(() => {
const RADIUSZOOM = .7;
const LINEWIDTH = 12;
let c = document.getElementById('c'),
  ctx = c.getContext('2d'),
  dpr = window.devicePixelRatio, //每一个css像素中包含的物理像素数
  br = document.getElementById('myChart').getBoundingClientRect(),
  cw = br.width,
  ch = br.height,
  mx = cw / 2,
  my = ch / 2;
c.width = cw * dpr;
c.height = ch * dpr;

// 角度转弧度
const toRadians = (a) => {
  return a * Math.PI / 180;
}

// 背景canvas
let bgc = document.createElement("canvas");
bgc.width = c.width;
bgc.height = c.height;
bgctx = bgc.getContext('2d');

// 绘制径向渐变背景
const drawGradialBg = (ctx) => {
  ctx.save();
  let gradial = ctx.createRadialGradient(mx, my, 1, mx, my, my);
  gradial.addColorStop(0, 'rgba(214,221,227,1)');
  gradial.addColorStop(1, 'rgba(214,221,227,0)');
  ctx.fillStyle = gradial;
  ctx.fillRect(0, 0, c.width, c.height);
}

// 绘制扇形渐变背景
const drawSectorBg = (ctx) => {
  ctx.save();
  ctx.translate(mx, my); // 坐标原点平移到中心
  ctx.rotate(toRadians(150)); // 中心旋转150度
  const sectorPoints = 40,
        sectorPerAngle = 240 / sectorPoints,
        S_R = 229, S_G = 235, S_B = 345,
        T_R = 251, T_G = 252, T_B = 253;
  for(let i = 1; i <= sectorPoints; i += 1) {
    let a = i * sectorPerAngle,
        b = (i - 1) * sectorPerAngle,
        r = mx * RADIUSZOOM,
        x1 = r * Math.cos(toRadians(a)),
        y1 = r * Math.sin(toRadians(a)),
        x2 = r * Math.cos(toRadians(b)),
        y2 = r * Math.sin(toRadians(b)),
        or = (T_R - S_R) / sectorPoints, og = (T_G - S_G) / sectorPoints, ob = (T_B - S_B) / sectorPoints;
    let g = ctx.createLinearGradient(x1, y1, x2, y2);
    g.addColorStop(0, `rgb(${S_R + i * or}, ${S_G + i * og}, ${S_B + i * ob})`);
    g.addColorStop(1, `rgb(${S_R + (i - 1) * or}, ${S_G + (i - 1) * og}, ${S_B + (i - 1) * ob})`);
    let o = .003
    ctx.beginPath();
    ctx.moveTo(0, 0);
    ctx.arc(0, 0, r, toRadians(b) - o, toRadians(a) - 0, false);
    ctx.fillStyle = g;
    ctx.closePath();
    ctx.fill();
  }
  ctx.restore();
}

// 创建表盘canvas
let guagec = document.createElement('canvas');
guagec.width = c.width;
guagec.height = c.height;
let guagectx = guagec.getContext('2d');
const textColorArr = ['#0057D0', '#0CC1FF', '#0FD262', '#96DD00', '#FFC000', '#FF4A90'];

// hex颜色表达式转rgb颜色数组
const hexToRgb =  (hex) => {
  hex = hex.replace(/^#/, '');
  let ret = [];
  for(let i = 0; i < hex.length; i += 2) {
    ret.push(Number(`0x${hex.substring(i, i + 2)}`));
  }
  return ret;
}
// 根据结束角度计算头部圆环颜色
const getColorByEndAngle = (endAngle, guagePerAngle) => {
  let tempEndAngle = endAngle + (Math.asin((LINEWIDTH) / (mx * (RADIUSZOOM + .1))) * 180 / Math.PI);
  tempEndAngle = tempEndAngle > 360 ? 360 : tempEndAngle;
  let relativePercentage = (tempEndAngle - 180) / guagePerAngle,
      endColorIndex = Math.ceil(relativePercentage),
      percentage = relativePercentage - Math.floor(relativePercentage);
  let startColor = hexToRgb(textColorArr[endColorIndex - 1]),
      endColor = hexToRgb(textColorArr[endColorIndex]);
  if(relativePercentage >= 5) {
    return `rgb(${endColor[0]}, ${endColor[1]}, ${endColor[2]})`;
  } else {
    let r = (endColor[0] - startColor[0]) * percentage + startColor[0],
    g = (endColor[1] - startColor[1]) * percentage + startColor[1],
    b = (endColor[2] - startColor[2]) * percentage + startColor[2];
    return `rgb(${r}, ${g}, ${b})`;
  }
}
// 绘制表盘头部圆环
const drawGuageBarCircle = (ctx, color, endAngle) => {
  ctx.save();
  let r = mx * RADIUSZOOM,
      x = r * Math.cos(toRadians(endAngle)) + mx,
      y = r * Math.sin(toRadians(endAngle)) + my;
  ctx.beginPath();
  ctx.shadowColor = 'rgba(218,218,218,1)';
  ctx.shadowBlur = 2;
  ctx.shadowOffsetY = 2;
  ctx.fillStyle = color; 
  ctx.arc(x, y, LINEWIDTH / 2 + 2, 0, 2 * Math.PI, true);
  ctx.closePath();
  ctx.fill();
  ctx.restore();
  ctx.fillStyle = 'white';
  ctx.beginPath();
  ctx.arc(x, y, LINEWIDTH / 2 - 3, 0, 2 * Math.PI, false);
  ctx.closePath();
  ctx.fill();
  ctx.restore();
}
// 绘制表盘
const drawGuage = (ctx, endAngle) => {
  ctx.save();
  let guagePoints = 5,
      guagePerAngle = 180 / guagePoints;
  ctx.font = '12px 思源黑体 CN Medium';
  ctx.textAlign = 'center';
  for(let i = 0; i <= guagePoints; i += 1) {
    let a = -i *  guagePerAngle,
        r = mx * (RADIUSZOOM + .1);
    ctx.fillStyle = textColorArr[i];
    ctx.fillText(i * 2, r * Math.cos(toRadians(180-a)) + mx, r * Math.sin(toRadians(180-a)) + my);
    ctx.fill();
  }

  let lg = ctx.createLinearGradient(mx * (1 - RADIUSZOOM), my, mx * (1 + RADIUSZOOM), my);
  lg.addColorStop(0, '#0057D0');
  lg.addColorStop(.2, '#0CC1FF');
  lg.addColorStop(.4, '#0FD262');
  lg.addColorStop(.6, '#96DD00');
  lg.addColorStop(.8, '#FFC000');
  lg.addColorStop(1, '#FF4A90');

  ctx.shadowColor = 'rgba(218,218,218,1)';
  ctx.shadowBlur = 2;
  ctx.shadowOffsetY = 2;
  ctx.lineWidth = LINEWIDTH;
  ctx.lineCap = 'round';
  ctx.strokeStyle = lg;
  ctx.beginPath();
  ctx.arc(mx, my, mx * RADIUSZOOM, toRadians(180), toRadians(endAngle), false);
  ctx.stroke();
  ctx.restore();
  drawGuageBarCircle(ctx, getColorByEndAngle(endAngle, guagePerAngle), endAngle);
}

// 绘制离屏背景
drawGradialBg(bgctx);
drawSectorBg(bgctx);

let curValue = 300;
  new TWEEN.Tween({v: 180}).to({v: curValue}, 1000)
  .easing(TWEEN.Easing.Quadratic.Out)
  .onUpdate((obj) => {
    // 绘制离屏表盘
    guagectx.clearRect(0, 0, c.width, c.height);
    drawGuage(guagectx, obj.v);
  }).start();

// 动画启动器
const animate = () => {
  ctx.clearRect(0, 0, c.width, c.height);
  var id = requestAnimationFrame(animate);
  var result = TWEEN.update();
  if(!result) cancelAnimationFrame(id);
  
  ctx.drawImage(bgc, 0, 0);
  ctx.drawImage(guagec, 0, 0);
}

animate();
})();